package model.surface;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

/**
 * Class representing the grid on the background, where the towers can be
 * placed. It is implemented with the singleton pattern.
 * 
 * @author EvilTeam
 * 
 */
public class Grid {

	private static final int FIX_BUG_FOR_NUMBER_OF_COLS = 1;
	private static final float SCALE_FACTOR_FOR_CELL_HEIGHT = 10.1f;
	private static final float SCALE_FACTOR_FOR_CELL_WIDTH = 14.9f;
	private static final int LINE_THICKNESS = 10;
	private static final String GRID_COLOR = "#0DFFFFFF";
	private static ScreenPoint[][] gridPoints;
	private static float widthOfTheCell;
	private static float heightOfTheCell;

	private static Grid grid = null;

	private Grid(int numberOfCells, int numberOfCols, float width, float height) {
		gridPoints = new ScreenPoint[numberOfCells + FIX_BUG_FOR_NUMBER_OF_COLS][numberOfCols];
		this.setWidthOfTheCell(width);
		this.setHeightOfTheCell(height);
		this.fillMyGrid();
	}

	/**
	 * Cleans the grid instance.
	 */
	public static void cleanGrid() {
		grid = null;
	}

	/**
	 * 
	 * @return Grid instance
	 */
	public static Grid getGridInstance() {
		return grid;
	}

	/**
	 * Setting up the grid for a first time.
	 * 
	 * @param numberOfCells
	 * @param numberOfCols
	 * @param width
	 *            - width of one cell in the grid
	 * @param height
	 *            - height of one cell in the grid
	 */
	public static void setGridInstance() {
		if (grid == null) {
			grid = new Grid(
					(int) (Scale.getScreenWidth() / (Scale.getScreenWidth() / SCALE_FACTOR_FOR_CELL_WIDTH)),
					(int) (Scale.getScreenHeight() / (Scale.getScreenHeight() / SCALE_FACTOR_FOR_CELL_HEIGHT)),
					(Scale.getScreenWidth() / SCALE_FACTOR_FOR_CELL_WIDTH),
					(Scale.getScreenHeight() / SCALE_FACTOR_FOR_CELL_HEIGHT));
		}
	}

	public void setWidthOfTheCell(float widthOfTheCell) {
		if (widthOfTheCell >= 0)
			Grid.widthOfTheCell = widthOfTheCell;
	}

	public void setHeightOfTheCell(float heightOfTheCell) {
		if (heightOfTheCell >= 0)
			Grid.heightOfTheCell = heightOfTheCell;
	}

	/**
	 * Used to fill the grid cells with default ScreenPoint objects, from where
	 * we can get the coordinates for current cell.
	 */
	private void fillMyGrid() {
		for (int row = 0; row < gridPoints.length; row++) {
			for (int col = 0; col < gridPoints[row].length; col++) {
				if (col == 0 || col == gridPoints[row].length - 1) {
					gridPoints[row][col] = new ScreenPoint(
							row * widthOfTheCell, col * heightOfTheCell, true);
				} else {
					gridPoints[row][col] = new ScreenPoint(
							row * widthOfTheCell, col * heightOfTheCell, false);
				}
			}
		}
	}

	/**
	 * Returns ScreenPoint with x, y coordinates where tower can be placed.
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public static ScreenPoint getTowerPoint(float x, float y) {
		for (int row = 0; row < gridPoints.length; row++) {
			for (int col = 0; col < gridPoints[row].length; col++) {
				if (isInScope(row, col, x, y)
						&& !gridPoints[row][col].isTaken()) {
					gridPoints[row][col].setTaken(true);
					return new ScreenPoint(gridPoints[row][col].getxPoint()
							+ (widthOfTheCell / 2),
							gridPoints[row][col].getyPoint()
									+ (heightOfTheCell / 2), true);
				}
			}
		}
		return null;
	}

	/**
	 * Sets the cell status - isTaken to false when a tower is sold and is no
	 * longer in the game.
	 * 
	 * @param x
	 * @param y
	 */
	public static void emptyCell(float x, float y) {
		for (int row = 0; row < gridPoints.length; row++) {
			for (int col = 0; col < gridPoints[row].length; col++) {
				if (isInScope(row, col, x, y)) {
					gridPoints[row][col].setTaken(false);
				}
			}
		}
	}

	/**
	 * Check's if the current point with x, y coordinates is in a certain cell.
	 * 
	 * @param row
	 *            - row of the cell
	 * @param col
	 *            - column of the cell
	 * @param x
	 * @param y
	 * @return
	 */
	private static boolean isInScope(int row, int col, float x, float y) {
		if (gridPoints[row][col].getxPoint() < x
				&& gridPoints[row][col].getyPoint() < y
				&& gridPoints[row][col].getxPoint() + widthOfTheCell >= x
				&& gridPoints[row][col].getyPoint() + widthOfTheCell >= y)
			return true;
		return false;
	}

	/**
	 * Draw's the grid on the game board, with transparent color and certain
	 * stroke width.
	 * 
	 * @param canvas
	 */
	public static void drawGrid(Canvas canvas) {

		Paint gridPaint = new Paint();
		gridPaint.setStrokeWidth(LINE_THICKNESS);
		gridPaint.setStyle(Paint.Style.STROKE);
		gridPaint.setColor(Color.parseColor(GRID_COLOR));

		for (int row = 0; row < gridPoints.length; row++) {
			canvas.drawLine(gridPoints[row][0].getxPoint(),
					gridPoints[row][0].getyPoint(), row * widthOfTheCell,
					Scale.getScreenHeight(), gridPaint);
		}

		for (int col = 0; col < gridPoints[0].length; col++) {
			canvas.drawLine(gridPoints[0][col].getxPoint(),
					gridPoints[0][col].getyPoint(), Scale.getScreenWidth(), col
							* heightOfTheCell, gridPaint);
		}
	}

	public static float getHeightOfTheCell() {
		return heightOfTheCell;
	}
}
